home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / procssng / compstol / cmpsttl1.lha / CompositeTool / v1.1.dist / HDF / df.c next >
Encoding:
C/C++ Source or Header  |  1990-05-08  |  44.8 KB  |  1,418 lines

  1. /*****************************************************************************
  2. *              NCSA HDF version 3.00
  3. *                December, 1989
  4. *
  5. * NCSA HDF Version 3.00 source code and documentation are in the public
  6. * domain.  Specifically, we give to the public domain all rights for future
  7. * licensing of the source code, all resale rights, and all publishing rights.
  8. * We ask, but do not require, that the following message be included in all
  9. * derived works:
  10. * Portions developed at the National Center for Supercomputing Applications at
  11. * the University of Illinois at Urbana-Champaign.
  12. * THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE
  13. * SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION,
  14. * WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE
  15. *****************************************************************************/
  16.  
  17. /*-----------------------------------------------------------------------------
  18.  * File:    df.c
  19.  * Purpose: HDF low level file access
  20.  * Invokes: df.h
  21.  * Contents: 
  22.  *  DFImemcopy: copy bytes, on machines with no memcpy equivalents
  23.  *  DFopen: open HDF file
  24.  *  DFclose: close HDF file
  25.  *  DFIseedDDs: read data descriptors into memory
  26.  *  DFIcheck: check that dfile is a valid HDF file pointer
  27.  *  DFdescriptors: return a list of the data descriptors in the HDF file
  28.  *  DFnumber: count the number of occurrences of a given tag in the HDF file
  29.  *  DFsetfind: set up a search
  30.  *  DFfind: search for tag/ref combination
  31.  *  DFIfind: internal routine to actually perform search
  32.  *  DFIemptyDD: find an empty DD in the HDF file, or create one
  33.  *  DFaccess: set up a read/write on a data element
  34.  *  DFstart: set up a read/write on a data element
  35.  *  DFread: read a portion of a data element
  36.  *  DFseek: seek to new position within data element
  37.  *  DFwrite: write portion of a data element
  38.  *  DFupdate: write out updated DDs to HDF file
  39.  *  DFstat: provide status information about HDF file
  40.  *  DFgetelement: read an entire data element
  41.  *  DFputelement: write an entire data element
  42.  *  DFdup: create an additional descriptor for a data element
  43.  *  DFdel: delete a data element
  44.  *  DFnewref: Get an unused reference number
  45.  *  DFishdf: is this an HDF file?
  46.  *  DFerrno: return value of DFerror
  47.  *  DFIerr: close a file saving DFerror, return -1, for error handling.
  48.  * Remarks: These are the only routines which access HDF files directly
  49.  *---------------------------------------------------------------------------*/
  50.  
  51. #define DFMASTER
  52. #include "df.h"
  53.  
  54. #define CKMALLOC( x, ret) { if (!x) { DFerror = DFE_NOSPACE; return(ret); } }
  55.  
  56. #define CKSEEK(x,y,z, ret)  {  if (DF_SEEK( x,(long)y,z) <0) \
  57.                 {DFerror = DFE_SEEKERROR; return(ret); } }
  58.  
  59. #define CKSEEKEND(x,y,z, ret)   {  if (DF_SKEND( x,(long)y,z) <0) \
  60.                 {DFerror = DFE_SEEKERROR; return(ret); } }
  61.  
  62. #ifdef VMS
  63. #define CKREAD(x,y,z,f, ret)    { \
  64.                 int32 currfileposn; \
  65.                 currfileposn = DF_TELL(f); \
  66.                 if (DF_READ( (char*)x, (int)(y), (int)(z), (f))<0) \
  67.                 { DFerror = DFE_READERROR; return(ret); } \
  68.                 DF_SEEK(f, (long) (currfileposn + y*z), 0); \
  69.                 }
  70. #else /*VMS*/
  71. #define CKREAD(x,y,z,f, ret)    { \
  72.                 if (DF_READ( (char*)x, (int)(y), (int)(z), (f))<0) \
  73.                 { DFerror = DFE_READERROR; return(ret); } \
  74.                 }
  75. #endif /*VMS*/
  76.  
  77. #define CKWRITE(x,y,z,f, ret)   { if (DF_WRITE( (char*)x, (int)y, (int)z,f)<0) \
  78.                 {DFerror = DFE_WRITEERROR; return(ret); } }
  79.  
  80. /*
  81.  *  Important Internal Variables
  82.  */
  83. static DF *DFlist=NULL;        /* pointer to list of open DFs */
  84. static int DFinuse=0;        /* How many are currently in use */
  85. static uint16 DFmaxref;        /* which is the largest ref used? */
  86. static unsigned char *DFreflist=NULL; /* list of refs in use */
  87. static char patterns[] = {0x80, 0x40, 0x20, 0x10, 0x08,
  88.                        0x04, 0x02, 0x01};
  89.  
  90. /*-----------------------------------------------------------------------------
  91.  * Name:    DFImemcopy
  92.  * Purpose: Copy bytes from one place to another
  93.  * Inputs:  from, to: source and destination for copy
  94.  *          length: number of bytes to copy
  95.  * Returns: 0 on success, -1 on failure with DFerror set
  96.  * Users:   HDF systems programmers, on machines without memcpy equivalents
  97.  * Remarks: assumes non-overlapping
  98.  *          Intended for machines on which memcppy etc. do not work
  99.  *---------------------------------------------------------------------------*/
  100.  
  101. DFImemcopy( from, to, length)
  102. char *from, *to;
  103. register int length;
  104. {
  105.     length++;
  106.     while (--length) *to++ = *from++;
  107.     return(0);
  108. }
  109.  
  110. /*-----------------------------------------------------------------------------
  111.  * Name:    DFopen
  112.  * Purpose: open DF file if it exists, else create it if write access
  113.  * Inputs:  name: name of file to open
  114.  *          access: DFACC_READ, DFACC_WRITE, DFACC_CREATE, DFACC_ALL
  115.  *          ndds: number of dds in a block
  116.  * Returns: DF ptr to open file on success, NULL on failure with DFerror set
  117.  * Invokes: DFIseedDDs 
  118.  * Users:   HDF programmers, many HDF user-level routines, utilities
  119.  * Remarks: Contains hooks for multiple DF files open simultaneously
  120.  *---------------------------------------------------------------------------*/
  121.  
  122. DF *DFopen( name, access, ndds )
  123. char *name;
  124. int access;
  125. int ndds;
  126. {
  127.     int created, i;             /* created is true if file is newly created */
  128.  
  129.                     /* error checking */
  130.     DFerror = DFE_NOERROR;
  131.  
  132.     if (!(*name)) {                             /* check name */
  133.         DFerror = DFE_BADNAME;
  134.         return(NULL);
  135.     }
  136.  
  137.     if ((access & (DFACC_ALL))!= access || access==0) {     /* check access */
  138.         DFerror = DFE_BADACC;
  139.         return(NULL); 
  140.     }
  141.     
  142.     if (DFinuse >= DF_MAXDFS) {    /* is DF table filled up? */
  143.         DFerror = DFE_TOOMANY; 
  144.         return(NULL);  
  145.     }
  146.     
  147.                 /* open file, set it up */
  148.         /* set up space for list of DFs */
  149.     if (!DFlist) {
  150.         DFlist = (DF *) malloc(DF_MAXDFS * sizeof(DF));
  151.         for (i=0; i<DF_MAXDFS; i++)
  152.             DFlist[i].type = 0;    /* mark free */
  153.     }
  154.  
  155.         /* locate unused slot in table */
  156.     for (i=0; i<DF_MAXDFS && DFlist[ i].type != 0; i++);
  157.  
  158.     if ( i>=DF_MAXDFS) {                            /* no free slot */
  159.         DFerror = DFE_TOOMANY;
  160.         return(NULL); 
  161.     }
  162.  
  163.     if (access == DFACC_CREATE) {
  164.         created = 1;
  165.         access = DFACC_WRITE;                   /* equivalent to write */
  166.     }
  167.     else created = 0;
  168.  
  169.         /* does an extra open just to check if file exists */
  170.     if (created || !(DFlist[i].file = DF_OPEN(name, DF_RDACCESS))) {
  171.         if (access<2) {         /* file does not exist, check if read access */
  172.             DFerror = DFE_FNF;  /* file not found */
  173.             return(NULL);
  174.         }
  175.         close (DF_CREAT( name, 0666));  /* else create the file */
  176.         created=1;
  177.     }
  178.     else
  179.         DF_CLOSE(DFlist[i].file);   /* open successful, close it */
  180.  
  181.         /* open file with correct access mode */
  182.     if ( !(DFlist[i].file = DF_OPEN( name, 
  183.         ((access>1) ? DF_WRACCESS : DF_RDACCESS ))) ) {
  184.         DFerror = DFE_BADOPEN;
  185.         return(NULL);
  186.     }
  187.  
  188.     if (created) {      /* Create a DDH and DD's for a new file */
  189.         DFdd dd;
  190.         DFddh ddh;
  191.     char magick[4];
  192.         int j;
  193.  
  194.     strncpy(magick, DF_MAGICK, 4); /* magick number */
  195.         CKWRITE( magick,4,1,DFlist[i].file, NULL);
  196.  
  197.         ddh.next=0;                         /* only one DDH */
  198.         if (ndds<=0) DFlist[i].defdds = DF_DEFAULTDDS;  
  199.         else DFlist[i].defdds = ndds;       /* set up number of DDs in block */
  200.         ddh.dds = DFlist[i].defdds;
  201.         dd.tag=DFTAG_NULL;              /* set up empty DD */
  202.         dd.ref=0;                       /* offset, length don't care */
  203.  
  204. #ifdef DF_STRUCTOK                      /* okay to write structures? */
  205.         CKWRITE( &ddh, sizeof(DFddh), 1, DFlist[i].file, NULL); /* write it */
  206. #else /*DF_STRUCTOK*/
  207.         {
  208.             register char *p;
  209.             /* copy structure into buffer, write it out */
  210.             p = DFtbuf;
  211.             INT16WRITE( p, ddh.dds);    /* header */
  212.             INT32WRITE( p, ddh.next);
  213.             CKWRITE( DFtbuf, 6, 1, DFlist[i].file, NULL);   /* 6=header size */
  214.         }
  215. #endif /*DF_STRUCTOK*/
  216.  
  217.         for (j=0; j<ddh.dds; j++) {             /* write out DDs */
  218. #ifdef DF_STRUCTOK
  219.             CKWRITE( &dd, sizeof(DFdd),1, DFlist[i].file, NULL);
  220. #else /*DF_STRUCTOK*/
  221.             {
  222.                 register char *p;
  223.                 p = DFtbuf;
  224.                 UINT16WRITE( p, dd.tag);
  225.                 UINT16WRITE( p, dd.ref);
  226.                 INT32WRITE( p, dd.offset);
  227.                 INT32WRITE( p, dd.length);
  228.                 CKWRITE( DFtbuf, 12, 1, DFlist[i].file, NULL); /* 12=DD size */
  229.             }
  230. #endif /*DF_STRUCTOK*/
  231.         }
  232.     }
  233.     else {            /* if file already exists */
  234.          char magick[4];
  235.  
  236.         CKREAD( magick, 4, 1, DFlist[i].file, NULL); /* check magick number */
  237.         if ( strncmp(magick,DF_MAGICK,4)) {
  238.             DFerror = DFE_NOTDFFILE;
  239.             DF_CLOSE(DFlist[i].file);
  240.             return(NULL);
  241.         }
  242.     }
  243.  
  244.     /* store status information in struct */
  245.     if (ndds<=0) DFlist[i].defdds = DF_DEFAULTDDS;  
  246.     else DFlist[i].defdds = ndds;
  247.     DFlist[i].access=access;
  248.     DFlist[i].list = NULL;
  249.     DFlist[i].changed=0;
  250.     DFlist[i].last_tag= 0;
  251.     DFlist[i].last_ref= 0;
  252.     DFlist[i].type=1;
  253.     DFlist[i].up_access=0;
  254.     DFlist[i].up_dd = NULL;
  255.  
  256.             /* read DDs and store the information in internal structure */
  257.     if (DFIseedDDs( &DFlist[i]) <0) return(NULL);
  258.  
  259.     if (created) {                  /* create MT if new file */
  260.         DFdd *dd;
  261.         dd = &(DFlist[i].list->next->dd[0]);    /* first dd is in 2nd dle */
  262.         dd->tag = DFTAG_MT;
  263.         dd->ref = DF_MT;
  264.         dd->offset = 0;
  265.         dd->length = 0;
  266.     }
  267.     DFinuse++;                      /* no of DF slots in use */
  268.     return( &DFlist[i]);            /* DF file pointer */
  269. }
  270.  
  271.  
  272. /*-----------------------------------------------------------------------------
  273.  * Name:    DFclose
  274.  * Purpose: Write out updated DDs, close DF file
  275.  * Inputs:  dfile: pointer to open DF file
  276.  * Returns: 0 on success, -1 on failure with DFerror set
  277.  * Invokes: DFIcheck
  278.  * Users:   HDF programmers, many HDF user-level routines, utilities
  279.  *---------------------------------------------------------------------------*/
  280.  
  281. int DFclose( dfile)
  282. DF *dfile;
  283. {
  284.     DFdle *prev, *current;          /* DLEs being written out */
  285.     int i;
  286.  
  287.     DFerror = DFE_NOERROR;
  288.  
  289.     if ( DFIcheck(dfile))           /* is dfile a valid pointer? */
  290.         return(-1);
  291.  
  292.     if (dfile->type!=1) {           /* 0 is a closed file  or unused slot */
  293.         DFerror= DFE_NOTOPEN;
  294.         return(-1);
  295.     }
  296.  
  297.     prev=dfile->list;               /* start of DLE list */
  298.  
  299.     while (current=prev->next) {        /* for all DLEs */
  300.         if (dfile->changed) {           /* if file modified, write it out */
  301.                 /* current DD should be written at location prev->ddh.next */
  302.             CKSEEK( dfile->file, (long) prev->ddh.next,0, -1);
  303.             if (current->ddh.dds) {     /* if any DDs to write out */
  304. #ifdef DF_STRUCTOK
  305.                 CKWRITE( ¤t->ddh, sizeof(DFddh)+
  306.                     current->ddh.dds*sizeof(DFdd), 1, dfile->file, -1);
  307. #else /*DF_STRUCTOK*/
  308.                 {           /* write out dd struct elements */
  309.                     register  char *p;
  310.                     p = DFtbuf;
  311.                     INT16WRITE( p, current->ddh.dds);
  312.                     INT32WRITE( p, current->ddh.next);
  313.                     for (i=0; i<current->ddh.dds; i++) {
  314.                         UINT16WRITE( p, current->dd[i].tag);
  315.                         UINT16WRITE( p, current->dd[i].ref);
  316.                         INT32WRITE( p, current->dd[i].offset);
  317.                         INT32WRITE( p, current->dd[i].length);
  318.                     }
  319.                     CKWRITE( DFtbuf, 6+i*12, 1, dfile->file, -1);
  320.                             /* 6=size of DDH, 12=size of DD */
  321.                 }
  322. #endif /*DF_STRUCTOK*/
  323.             }
  324.         }
  325.         DFIfreespace((char*)prev);
  326.         prev=current;
  327.     }
  328.     DFIfreespace((char*)prev); /* get rid of the last one */
  329.  
  330.     if ( (DF_CLOSE( dfile->file)) !=0) {
  331.         DFerror = DFE_CANTCLOSE;
  332.         return(-1);
  333.     }
  334.  
  335.                     /* reset structure values */
  336.     dfile->last_ref= 0;
  337.     dfile->last_tag= 0;
  338.     dfile->type=0;
  339.     dfile->access=0;
  340.     dfile->file= 0;
  341.     dfile->list= (DFdle *) 0L;
  342.     DFinuse--;
  343.     return(0);
  344. }   
  345.  
  346.  
  347. /*-----------------------------------------------------------------------------
  348.  * Name:    DFIseedDDs
  349.  * Purpose: read DDs in file into memory
  350.  * Inputs:  dfile: pointer to open DF file
  351.  * Returns: 0 on success, -1 on failure with DFerror set
  352.  * Users:   HDF systems programmers, DFopen
  353.  *---------------------------------------------------------------------------*/
  354.  
  355. int DFIseedDDs(dfile)
  356. DF *dfile;
  357. {
  358.     DFdle *list;
  359.     DFddh ddh;
  360.     int i,n;                        /* n = no. of DDs in block */
  361.     
  362.     DFerror = DFE_NOERROR;
  363.  
  364.     if (dfile->list) {
  365.         DFerror = DFE_SEEDTWICE;    /* ### NOTE: Internal error! */
  366.         return(-1);
  367.     }
  368.     
  369.     dfile->list= (DFdle *) malloc(sizeof(DFdle)); /* includes one DD - unused */
  370.     CKMALLOC( dfile->list, -1);
  371.  
  372.     list=dfile->list;
  373.     list->next=NULL;                /* No other lists (yet) */
  374.     list->ddh.next= (int32)4L;      /* next is at 4 in file */
  375.     list->ddh.dds= -1;              /* flag so this is not written */
  376.  
  377.     DFmaxref = 0;                   /* largest ref found till now is 0 */
  378.  
  379.     while (list->ddh.next) {        /* while more headers to read */
  380.         CKSEEK( dfile->file, list->ddh.next, 0, -1);
  381.  
  382.                             /* read headers */
  383. #ifdef DF_STRUCTOK
  384.         CKREAD( &ddh, sizeof(DFddh), 1, dfile->file, -1);
  385. #else /*DF_STRUCTOK*/
  386.         {
  387.             register  char *p;
  388.             p = DFtbuf;
  389.             CKREAD( DFtbuf, 6, 1, dfile->file, -1);     /* 6 = size of header */
  390.             INT16READ( p, ddh.dds);
  391.             INT32READ( p, ddh.next);
  392.         }
  393. #endif /*DF_STRUCTOK*/
  394.         n   =ddh.dds;
  395.  
  396.     /* read in DDs */
  397.         list->next= (DFdle *)
  398.         DFIgetspace((unsigned)
  399.             (sizeof(DFdle)+ (n-1)* sizeof(DFdd)));
  400.                 /* note space for 1 DD included in DLE */
  401.         CKMALLOC( list->next, -1);
  402.         list=list->next;
  403.         list->next=NULL;
  404.     
  405.         DFmovmem((char*)&ddh, (char*)&(list->ddh),
  406.          sizeof(DFddh) ); /* Copy ddh */
  407.  
  408.         if (n) {
  409. #ifdef DF_STRUCTOK
  410.             CKREAD( &list->dd[0], sizeof(DFdd), n, dfile->file, -1);
  411.         /* load DD's */
  412. #else /*DF_STRUCTOK*/
  413.             {
  414.                 register  char *p;
  415.                 p = DFtbuf;
  416.                 CKREAD( DFtbuf, n*12, 1, dfile->file, -1);  /* 12=size of DD */
  417.                 for (i=0; i<n; i++) {
  418.                     UINT16READ( p, list->dd[i].tag);
  419.                     UINT16READ( p, list->dd[i].ref);
  420.                     INT32READ( p, list->dd[i].offset);
  421.                     INT32READ( p, list->dd[i].length);
  422.                 }
  423.             }
  424. #endif /*DF_STRUCTOK*/
  425.         }
  426.                 /* Remember highest ref found - ignore MTs */
  427.         for (i=0; i<n; i++)
  428.             if ((list->dd[i].ref > DFmaxref) && (list->dd[i].tag != DFTAG_MT))
  429.                                      DFmaxref = list->dd[i].ref;
  430.     }
  431.     return(0);
  432. }
  433.  
  434.  
  435. /*-----------------------------------------------------------------------------
  436.  * Name:    DFIcheck
  437.  * Purpose: check if dfile argument represents a valid DF file
  438.  * Inputs:  dfile: pointer to open DF file
  439.  * Returns: 0 on success, -1 on failure with DFerror set
  440.  * Users:   HDF systems programmers, several routines in this file
  441.  *---------------------------------------------------------------------------*/
  442.  
  443. int DFIcheck( dfile)
  444. DF *dfile;
  445. {
  446.     DFerror = DFE_NOERROR;
  447.     
  448.     if (!dfile) {
  449.         DFerror = DFE_DFNULL;
  450.         return(-1);
  451.         }
  452.  
  453.     if ((dfile->access & DFACC_ALL) != dfile->access)
  454.         DFerror = DFE_BADACC;
  455.  
  456.     if ((dfile->type >1) || (dfile->type <-1))
  457.         DFerror = DFE_ILLTYPE;
  458.  
  459.     if (!dfile->list)
  460.         DFerror= DFE_BADDDLIST;
  461.  
  462.     if (DFerror)
  463.         return(-1);
  464.     else
  465.         return(0);
  466.  
  467. }
  468.  
  469.  
  470. /*-----------------------------------------------------------------------------
  471.  * Name:    DFdescriptors
  472.  * Purpose: return a list of all the DDs in the file
  473.  * Inputs:  dfile: pointer to open DF file
  474.  *          ptr: pointer to space for the list of DDs
  475.  *          begin, num: the list starts at DD numbered begin, and contains
  476.  *              a maximum of num entries
  477.  * Returns: number of DDs returned in the list
  478.  * Invokes: DFIcheck
  479.  * Users:   HDF programmers, other routines and utilities
  480.  *---------------------------------------------------------------------------*/
  481.  
  482. int DFdescriptors(dfile, ptr, begin, num)
  483. DF *dfile;
  484. DFdesc ptr[];
  485. int begin, num;
  486. {
  487.     DFdle *DLEp;
  488.     int i,ddnum=0;
  489.  
  490.     if ( DFIcheck(dfile))
  491.         return(-1);
  492.     
  493.     if (begin<0) begin = 0;
  494.     if (num<0) num = 0;
  495.     ddnum = 0;
  496.     for (DLEp=dfile->list; DLEp; DLEp=DLEp->next)
  497.         for (i=0; i<DLEp->ddh.dds; i++, ddnum++)
  498.             if (ddnum>=begin) {
  499.                 if (ddnum<begin+num) {
  500.                     ptr[ddnum-begin] = DLEp->dd[i];
  501.                 }
  502.                 else
  503.                     return(num);
  504.             }
  505.     return(ddnum-begin);
  506. }
  507.  
  508.  
  509. /*-----------------------------------------------------------------------------
  510.  * Name:    DFnumber
  511.  * Purpose: return the number of occurrences of the given tag in the HDF file
  512.  * Inputs:  dfile: pointer to open DF file
  513.  *          tag: tag to count occurrences of
  514.  * Returns: number of occurrences of tag in file, -1 on error with DFerror set
  515.  *          if tag is DFTAG_WILDCARD, count occurrences of all tags
  516.  * Invokes: DFIcheck
  517.  * Users:   HDF programmers, other routines and utilities
  518.  *---------------------------------------------------------------------------*/
  519.  
  520. int DFnumber(dfile, tag)
  521. DF *dfile;
  522. uint16 tag;
  523. {
  524.     DFdle *DLEp;
  525.     int i, ntag=0;
  526.  
  527.     if ( DFIcheck(dfile))
  528.         return(-1);
  529.     
  530.     for (DLEp=dfile->list; DLEp; DLEp=DLEp->next)
  531.         if (tag==DFTAG_WILDCARD) ntag += DLEp->ddh.dds;
  532.         else {
  533.             for (i=0; i<DLEp->ddh.dds; i++)
  534.                 if (DLEp->dd[i].tag == tag) ntag++;
  535.         }
  536.  
  537.     return(ntag);
  538. }
  539.  
  540.  
  541. /*-----------------------------------------------------------------------------
  542.  * Name:    DFsetfind
  543.  * Purpose: set up parameters for a wildcard find
  544.  * Inputs:  dfile: pointer to open DF file
  545.  *          tag, ref: tag and ref of element to search for, 0 is wildcard
  546.  * Returns: 0 on success, -1 on failure
  547.  * Invokes: DFIcheck
  548.  * Users:   HDF programmers, several utilities
  549.  *---------------------------------------------------------------------------*/
  550.  
  551. int DFsetfind( dfile, tag, ref)
  552. DF *dfile;
  553. uint16 tag,ref;
  554. {
  555.  
  556.     if ( DFIcheck(dfile))
  557.         return(-1);
  558.     
  559.         /* remember tag, ref for subsequent searches */
  560.     dfile->last_tag=tag;
  561.     dfile->last_ref=ref;
  562.     dfile->last_dle=NULL;           /* flag value: nothing found so far */
  563.  
  564.     return(0);
  565. }
  566.     
  567.  
  568. /*-----------------------------------------------------------------------------
  569.  * Name:    DFfind
  570.  * Purpose: perform wildcard searches - sets up parameters, calls DFIfind
  571.  * Inputs:  dfile: pointer to open DF file
  572.  *          ptr: ptr to put in DD when found
  573.  * Returns: 0 on success, -1 on failure
  574.  *          if success, DD matching specification is copied to *ptr
  575.  * Invokes: DFIcheck, DFIfind
  576.  * Users:   HDF programmers, several utilities
  577.  *---------------------------------------------------------------------------*/
  578.  
  579. int DFfind(dfile, ptr)
  580. DF *dfile;
  581. struct DFdesc *ptr;
  582. {
  583.     DFdle *cDLEp;
  584.     int cdd;
  585.     uint16 tag, ref, ltag,lref;
  586.     int isfirst=1;
  587.  
  588.     if ( DFIcheck(dfile))
  589.         return(-1);
  590.  
  591.     DFerror = DFE_NOERROR;
  592.  
  593.     tag = dfile->last_tag;          /* tag, ref being searched for */
  594.     ref = dfile->last_ref;
  595.  
  596.     if (dfile->last_dle) {          /* something found previously */
  597.         isfirst = 0;
  598.         ltag= dfile->last_dle->dd[ dfile->last_dd ].tag;    /* prev tag, ref */
  599.         lref= dfile->last_dle->dd[ dfile->last_dd ].ref;
  600.     } else {
  601.     ltag = lref = 0;
  602.     }
  603.  
  604.     if ((tag!=DFTAG_NULL) &&        /* empty DDs are invisible on finds */
  605.         !DFIfind( dfile, tag, ref, isfirst, ltag, lref, &cDLEp, &cdd)) {
  606.         *ptr = cDLEp->dd[cdd];      /* if found, copy dd to ptr */
  607.         dfile->last_dd = cdd;       /* set last_dle and last_dd to DD found */
  608.         dfile->last_dle= cDLEp;
  609.         return(0);
  610.     } else {
  611.         DFerror = DFE_NOMATCH;
  612.         ptr->tag = 0;
  613.         ptr->ref = 0;
  614.         return(-1);
  615.     }
  616. }
  617.         
  618.  
  619. /*-----------------------------------------------------------------------------
  620.  * Name:    DFIfind
  621.  * Purpose: perform wildcard searches
  622.  * Inputs:  dfile: pointer to open DF file
  623.  *          tag, ref: tag, ref (possibly wildcard) being searched for
  624.  *          isfirst: 1 if first call to DFIfind for this tag/ref, else 0
  625.  *          ltag, lref: last tag and ref returned for this search,
  626.  *              don't care if isfirst set
  627.  *          cDLEp, cddp: pointers to DLE and DD number to return matched DD in
  628.  * Returns: 0 on success, -1 on failure
  629.  *          if success, cDLEp and cddp are set to point to matched DD
  630.  * Users:   HDF system programmers, DFfind, HDF utilities, many routines
  631.  * Remarks: The searching algorithm is a little complex.  It returns entries
  632.  *          in the sorting order of refs, then tags.  Even after a candidate
  633.  *          is found, searching continues till best candidate found.  Best way
  634.  *          to check if conditions: work it out independently for yourself!
  635.  *---------------------------------------------------------------------------*/
  636.  
  637. int DFIfind( dfile, tag, ref, isfirst, ltag, lref, cDLEp, cddp)
  638. DF *dfile;
  639. DFdle **cDLEp;
  640. int *cddp;
  641. int isfirst;                            /* 1 if no prev search, 0 otherwise */
  642. uint16 tag, ref, ltag, lref;
  643. {
  644.     DFdle *DLEp;
  645.     int i, found=0;
  646.     uint16 ctag=0, cref=0, wtag,wref; /* ctag, cref: tag, ref found so far */
  647.                                       /* wtag, wref: tag, ref being checked */
  648.  
  649.     DLEp=dfile->list;               /* start of DLE list */
  650.  
  651.     if (tag && ref) {               /* No wildcards */
  652.         if (isfirst) {              /* if not already found */
  653.             while (DLEp) {          /* go through list */
  654.                 for (i=0; i<DLEp->ddh.dds; i++) {       /* for all DDs */
  655.                     if (DLEp->dd[i].tag==tag &&
  656.                             DLEp->dd[i].ref==ref)
  657.                         {*cDLEp=DLEp; *cddp=i; return(0);}
  658.                     }
  659.                 DLEp=DLEp->next;
  660.                 }
  661.             }
  662.         }
  663.     else if (tag && !ref)           /* wildcard ref */
  664.         while (DLEp) {
  665.             for (i=0; i<DLEp->ddh.dds; i++) {
  666.                 wtag=DLEp->dd[i].tag;
  667.                 wref=DLEp->dd[i].ref;
  668.         /* condition = tag match, better than found so far (if any),
  669.             follows what was returned last time (if any) */
  670.                 if ( (wtag==tag) && (!found || (wref<cref)) &&
  671.                     (isfirst || (wref>lref)))
  672.                     { ctag=wtag; cref=wref; *cDLEp=DLEp; *cddp=i;found=1;}
  673.                 }
  674.             DLEp=DLEp->next;
  675.             }
  676.     else if (!tag && ref)           /* wildcard tag */
  677.         while (DLEp) {
  678.             for (i=0; i<DLEp->ddh.dds; i++) {
  679.                 wtag=DLEp->dd[i].tag;
  680.                 wref=DLEp->dd[i].ref;
  681.                 if ((wref==ref) && (isfirst || (wtag>ltag)) &&
  682.                     (!found || (wtag<ctag)) )
  683.                     { ctag=wtag; cref=wref; *cDLEp=DLEp; *cddp=i;found=1;}
  684.                 }
  685.             DLEp=DLEp->next;
  686.             }
  687.     else if (!tag && !ref)          /* wildcard tag & ref */
  688.         while (DLEp) {
  689.             for (i=0; i<DLEp->ddh.dds; i++) {
  690.                 wtag=DLEp->dd[i].tag;
  691.                 wref=DLEp->dd[i].ref;
  692.                 if ((isfirst || (wref>lref) || (wref==lref && wtag>ltag)) &&
  693.                     (!found || (wref<cref) || (wref==cref && wtag<ctag)) &&
  694.                     (wtag!=DFTAG_NULL))         /* empty DDs are invisible */
  695.                     { ctag=wtag; cref=wref; *cDLEp=DLEp; *cddp=i;found=1;}
  696.                 }
  697.             DLEp=DLEp->next;
  698.             }
  699.     return(found-1);            /* 0 or -1 */
  700. }
  701.  
  702.  
  703. /*-----------------------------------------------------------------------------
  704.  * Name:    DFIemptyDD
  705.  * Purpose: find an empty DD to use, or create a block of DDs if necessary
  706.  * Inputs:  dfile: pointer to open DF file
  707.  * Returns: pointer to an empty DD
  708.  * Invokes: DFIfind
  709.  * Users:   HDF system programmers, DFaccess, DFdup
  710.  *---------------------------------------------------------------------------*/
  711.  
  712. DFdd *DFIemptyDD(dfile)
  713. DF *dfile;
  714. {
  715.     DFdle *cDLEp;
  716.     int cdd;
  717.  
  718.     if (!DFIfind( dfile, DFTAG_NULL, DFREF_WILDCARD, 1, 0, 0, &cDLEp, &cdd))
  719.         return(&(cDLEp->dd[cdd]));      /* there is an empty DD */
  720.  
  721.     else {          /* add new DDH block */
  722.         int32 fpos;
  723.         DFdle *p, *dle;
  724.         DFddh ddh;
  725.         DFdd dd;
  726.         int j;
  727.  
  728.         CKSEEKEND( dfile->file, (long) 0, 2, NULL); /* go to end of df */
  729.         fpos= (int32) DF_TELL(dfile->file);
  730.         ddh.dds= dfile->defdds;             /* Initialize ddh */
  731.         ddh.next= 0;
  732.         dd.tag=DFTAG_NULL;                  /* and all DD's */
  733.         dd.ref=0;
  734. #ifdef DF_STRUCTOK
  735.         CKWRITE( &ddh, sizeof(DFddh), 1, dfile->file, NULL);
  736. #else /*DF_STRUCTOK*/
  737.         {
  738.             register  char *p;
  739.             p = DFtbuf;
  740.             INT16WRITE( p, ddh.dds);
  741.             INT32WRITE( p, ddh.next);
  742.             CKWRITE( DFtbuf, 6, 1, dfile->file, NULL);  /* 6 = size of header */
  743.         }
  744. #endif /*DF_STRUCTOK*/
  745.         for (j=0; j<ddh.dds; j++) {
  746. #ifdef DF_STRUCTOK
  747.             CKWRITE( &dd, sizeof(DFdd),1, dfile->file, NULL);
  748. #else /*DF_STRUCTOK*/
  749.             {
  750.                 register  char *p;
  751.                 p = DFtbuf;
  752.                 UINT16WRITE( p, dd.tag);
  753.                 UINT16WRITE( p, dd.tag);
  754.                 INT32WRITE( p, dd.offset);
  755.                 INT32WRITE( p, dd.length);
  756.                 CKWRITE( DFtbuf, 12, 1, dfile->file, NULL); /* 12=size of dd */
  757.             }
  758. #endif /*DF_STRUCTOK*/
  759.         }
  760.  
  761.         p=dfile->list;                      /* find end of list */
  762.         while (p->next) p= p->next;
  763.  
  764.         p->ddh.next=fpos;                   /* new dd goes at end of file */
  765.         dle=(DFdle *)
  766.         DFIgetspace((unsigned)
  767.             (sizeof(DFdle)+(ddh.dds-1)*sizeof(DFdd)));
  768.                             /* one dd included in dle */
  769.         CKMALLOC(dle, NULL);
  770.         p->next=dle;                        /* insert dle at end of list */
  771.         dle->next=NULL;
  772.         DFmovmem((char*)&ddh, (char*)&dle->ddh,sizeof(DFddh));
  773.         for (j=0; j<ddh.dds; j++)
  774.             DFmovmem( (char*)&dd, (char*)&dle->dd[j], sizeof(DFdd));
  775.         return(&(dle->dd[0]));
  776.     }
  777. #ifdef PC
  778.     return(NULL);           /* dummy, for return value checking */
  779. #endif /*PC*/
  780. }
  781.  
  782.  
  783. /*-----------------------------------------------------------------------------
  784.  * Name:    DFaccess
  785.  * Purpose: set up read/write access to a data element
  786.  * Inputs:  dfile: pointer to open DF file
  787.  *          tag, ref: id of element
  788.  *          access: "r", "w", "a" (append)
  789.  * Returns: 0 on success, -1 on failure
  790.  * Invokes: DFIcheck, DFIfind, DFIemptyDD
  791.  * Users:   HDF programmers, utilities, DFgetelement, DFputelement
  792.  * Remarks: if "a", data element will be copied to end of file, since it
  793.  *          cannot be extended in place if it is in the middle of the file
  794.  *---------------------------------------------------------------------------*/
  795.  
  796. int DFaccess(dfile, tag, ref, access)
  797. DF *dfile;
  798. uint16 tag, ref;
  799. char *access;
  800. {
  801.     DFdle *cDLEp;
  802.     int cdd;
  803.      char *storage=NULL;        /* for copying data if append access */
  804.     char accmode;
  805.     
  806.     DFerror = DFE_NOERROR;
  807.  
  808.     if (DFIcheck(dfile) )
  809.         return( -1);
  810.  
  811.     if (!tag) {
  812.         DFerror = DFE_BADTAG;
  813.         return(-1);
  814.     }
  815.     if (!ref) {
  816.         DFerror = DFE_BADREF;
  817.         return(-1);
  818.     }
  819.             /* set up and check access modes */
  820.     accmode = *access;
  821.     switch (accmode) {
  822.         case 'r':   dfile->up_access = DFACC_READ;  break;
  823.         case 'a':
  824.         case 'w':   dfile->up_access = DFACC_WRITE; break;
  825.         default:    DFerror = DFE_BADACC;   return(-1); 
  826.     }
  827.     if ((dfile->up_access & dfile->access) != dfile->up_access) {
  828.         DFerror = DFE_BADACC;
  829.         return(-1);
  830.     }
  831.                     
  832.                 /* Find DD of element to be updated */
  833.     if (!DFIfind( dfile, tag, ref, 1, 0 , 0, &cDLEp, &cdd))
  834.         dfile->up_dd = &(cDLEp->dd[cdd]);   /* DD of element to be updated */
  835.  
  836.     else {              /* No such DD */
  837.         if (accmode=='r') {
  838.             DFerror = DFE_NOMATCH; 
  839.             return(-1);
  840.         }
  841.         accmode = 'w';          /* append is really write if no current data */
  842.         dfile->up_dd = DFIemptyDD(dfile);       /* find an empty DD to use */
  843.         if (!dfile->up_dd) return(-1);
  844.         dfile->up_dd->tag = tag;                    /* fill in DD block */
  845.         dfile->up_dd->ref = ref;
  846.         dfile->up_dd->length = 0;
  847.     }
  848.  
  849.     if (accmode!='w') {        /*for read, DFaccess positions fp at element */
  850.                                 /* for append also, we need to read element */
  851.         CKSEEK(dfile->file, (long) dfile->up_dd->offset, 0, -1);
  852.         }
  853.     else dfile->up_dd->length = 0;  /* throws away any existing data */
  854.  
  855.     if (accmode!='r') {
  856.         dfile->changed = 1;         /* if write/append, file modified */
  857.  
  858.         if ((accmode=='a') && (dfile->up_dd->length)) {
  859.                     /* allocate storage to read current data */
  860.                 storage = (char*)DFIgetspace((unsigned)(dfile->up_dd->length));
  861.                 CKMALLOC( storage, -1 );
  862.                 CKREAD( storage, dfile->up_dd->length, 1, dfile->file, -1);
  863.         }
  864.  
  865.         CKSEEKEND( dfile->file, (long) 0, 2, -1);   /* go to end of df */
  866.             /* find the offset of the end of file */
  867.         dfile->up_dd->offset = (int32) DF_TELL(dfile->file);
  868.  
  869.         if ((accmode=='a') && dfile->up_dd->length) {   /* copy old data */
  870.             CKWRITE( storage, dfile->up_dd->length, 1, dfile->file, -1);
  871.                 /* note this leaves fp positioned correctly for write */
  872.         }
  873.         if (storage) DFIfreespace(storage);
  874.     }
  875.  
  876.     if (DFmaxref < ref) DFmaxref = ref;                 /* note ref is used */
  877.     if (DFreflist) DFreflist[ref/8] |= patterns[ref%8]; /* set ref'th bit */
  878.  
  879.     return(0);
  880. }
  881.  
  882.  
  883. /*-----------------------------------------------------------------------------
  884.  * Name:    DFstart
  885.  * Purpose: set up read/write access to a data element - alternate to DFaccess
  886.  * Inputs:  dfile: pointer to open DF file
  887.  *          tag, ref: id of element
  888.  *          access: "r", "w", "a" (append)
  889.  * Returns: 0 on success, -1 on failure
  890.  * Invokes: DFaccess
  891.  * Users:   Accidental/old-time users, intending to use DFaccess
  892.  * Remarks: none
  893.  *---------------------------------------------------------------------------*/
  894.  
  895. int DFstart(dfile, tag, ref, access)
  896. DF *dfile;
  897. uint16 tag, ref;
  898. char *access;
  899. {
  900.  
  901.     return(DFaccess(dfile, tag, ref, access));
  902. }
  903.         
  904.  
  905. /*-----------------------------------------------------------------------------
  906.  * Name:    DFread
  907.  * Purpose: read bytes from DF file (part of element specified by DFaccess)
  908.  * Inputs:  dfile: pointer to open DF file
  909.  *          ptr: pointer to space to read data into
  910.  *          len: number of bytes to read
  911.  * Returns: number of bytes read on success, -1 on failure
  912.  * Invokes: DFIcheck
  913.  * Users:   HDF programmers, DFgetelement
  914.  *---------------------------------------------------------------------------*/
  915.  
  916. int32 DFread( dfile, ptr, len)
  917. DF *dfile;
  918. char *ptr;
  919. int32 len;
  920. {
  921.     int32 maxlen;
  922. #ifdef VMS
  923.     int32 totalread;
  924.     int32 readsize;
  925. #endif /*VMS*/
  926.  
  927.     DFerror = DFE_NOERROR;
  928.  
  929.     if (DFIcheck(dfile) )
  930.         return( (int32) -1);
  931.  
  932.     if (!dfile->up_dd) {
  933.         DFerror = DFE_BADCALL;
  934.         return((int32) -1);
  935.     }
  936.  
  937.     if (!(dfile->up_access & DFACC_READ)) {
  938.         DFerror = DFE_BADACC;
  939.         return((int32) -1);
  940.     }
  941.  
  942.     if (!ptr) {
  943.         DFerror = DFE_BADPTR;
  944.         return((int32) -1);
  945.     }
  946.  
  947.     maxlen = dfile->up_dd->length -
  948.                 ((int32) DF_TELL(dfile->file) - dfile->up_dd->offset);
  949.     if (len>maxlen) len = maxlen;
  950.     if (len<0) {            /* will also catch reads from beyond element */
  951.         DFerror = DFE_BADLEN;
  952.         return(-1);
  953.     }
  954.  
  955. #ifdef VMS
  956.     totalread = 0;
  957.     while (totalread<len) {
  958.         readsize = len - totalread;
  959.         if (readsize>512) readsize = 512;
  960.         CKREAD( &ptr[totalread], (int)readsize, 1, dfile->file, -1); 
  961.         totalread += readsize;
  962.     }
  963.         
  964. #else /*VMS*/
  965.     if (len) {      /* NOTE: cast to (int) will limit to 64K on 16 bit m/cs */
  966.         CKREAD( ptr, (int) len, 1, dfile->file, -1); 
  967.     }
  968. #endif /*VMS*/
  969.  
  970.     return(len);
  971. }
  972.  
  973.  
  974. /*-----------------------------------------------------------------------------
  975.  * Name:    DFseek
  976.  * Purpose: seek to a position, within element specified by DFaccess
  977.  * Inputs:  dfile: pointer to open DF file
  978.  *          offset: offset from beginning of element
  979.  * Returns: offset of actual position seek'ed to from beginning of element
  980.  * Invokes: DFIcheck
  981.  * Users:   HDF programmers
  982.  *---------------------------------------------------------------------------*/
  983.  
  984. int32 DFseek( dfile, offset)
  985. DF *dfile;
  986. int32 offset;
  987. {
  988.     
  989.     DFerror = DFE_NOERROR;
  990.  
  991.     if (DFIcheck(dfile) )
  992.         return( -1);
  993.  
  994.     if (!dfile->up_dd) {
  995.         DFerror = DFE_BADCALL;
  996.         return(-1);
  997.     }
  998.  
  999.     if (!(dfile->up_access & DFACC_READ)) {
  1000.         DFerror = DFE_BADACC;
  1001.         return(-1);
  1002.     }
  1003.  
  1004.     if (offset > dfile->up_dd->length) {
  1005.         offset = dfile->up_dd->length;
  1006.         DFerror = DFE_BADSEEK;
  1007.     }
  1008.  
  1009.     CKSEEK( dfile->file, (long) dfile->up_dd->offset + offset, 0, -1);
  1010.     return(offset);
  1011. }
  1012.  
  1013.  
  1014. /*-----------------------------------------------------------------------------
  1015.  * Name:    DFwrite
  1016.  * Purpose: write bytes to DF file (part of element specified by DFaccess)
  1017.  * Inputs:  dfile: pointer to open DF file
  1018.  *          ptr: pointer to data to be written
  1019.  *          len: number of bytes to written
  1020.  * Returns: number of bytes written on success, -1 on failure
  1021.  * Invokes: DFIcheck
  1022.  * Users:   HDF programmers, DFputelement
  1023.  *---------------------------------------------------------------------------*/
  1024.  
  1025. int32 DFwrite( dfile, ptr, len)
  1026. DF *dfile;
  1027. char *ptr;
  1028. int32 len;
  1029. {
  1030. #ifdef VMS
  1031.     int32 totalwritten;
  1032.     int32 writesize;
  1033. #endif /*VMS*/
  1034.  
  1035.     DFerror = DFE_NOERROR;
  1036.  
  1037.     if (DFIcheck(dfile) )
  1038.         return( -1);
  1039.  
  1040.     if (!(dfile->up_dd)) {
  1041.         DFerror = DFE_BADCALL;
  1042.         return(-1);
  1043.     }
  1044.  
  1045.     if (!(dfile->up_access & DFACC_WRITE)) {
  1046.         DFerror = DFE_RDONLY;
  1047.         return(-1);
  1048.     }
  1049.  
  1050.     if (!ptr) {
  1051.         DFerror = DFE_BADPTR;
  1052.         return(-1);
  1053.     }
  1054.  
  1055.     if (len<0) {
  1056.         DFerror = DFE_BADLEN;
  1057.         return(-1);
  1058.     }
  1059.  
  1060.     if (!(dfile->changed)) {        /* if an update between writes, re-seek */
  1061.       CKSEEK( dfile->file, (long) dfile->up_dd->offset + dfile->up_dd->length,
  1062.             0, -1);
  1063.     }
  1064.  
  1065. #ifdef VMS
  1066.     totalwritten = 0;
  1067.     while (totalwritten<len) {
  1068.         writesize = len - totalwritten;
  1069.         if (writesize>512) writesize = 512; /* write at most 512 at a time */
  1070.         CKWRITE( &ptr[totalwritten], (int)writesize, 1, dfile->file, -1); 
  1071.         totalwritten += writesize;
  1072.     }
  1073. #else /*VMS*/
  1074.     if (len) { CKWRITE( ptr, len, 1, dfile->file, -1); }
  1075. #endif /*VMS*/
  1076.     dfile->up_dd->length += len;
  1077.     return(len);
  1078. }
  1079.  
  1080.  
  1081. /*-----------------------------------------------------------------------------
  1082.  * Name:    DFupdate
  1083.  * Purpose: write out updated DD blocks to file
  1084.  * Inputs:  dfile: pointer to open DF file
  1085.  * Returns: 0 on success, -1 on failure
  1086.  * Invokes: DFIcheck
  1087.  * Users:   HDF programmers
  1088.  *---------------------------------------------------------------------------*/
  1089.  
  1090. int DFupdate( dfile)
  1091. DF *dfile;
  1092. {
  1093.     DFdle *prev, *current;
  1094.     int i;
  1095.  
  1096.     DFerror = DFE_NOERROR;
  1097.  
  1098.     if ( DFIcheck(dfile))
  1099.         return(-1);
  1100.  
  1101.     if (dfile->type!=1) {
  1102.         DFerror= DFE_NOTOPEN;
  1103.         return(-1);
  1104.     }
  1105.  
  1106.     prev=dfile->list;           /* start of DLE list */
  1107.  
  1108.     if (dfile->changed) {           /* modified */
  1109.         while (current=prev->next) {
  1110.             CKSEEK( dfile->file, (long) prev->ddh.next,0, -1);
  1111.             if (current->ddh.dds) {
  1112. #ifdef DF_STRUCTOK
  1113.                 CKWRITE( ¤t->ddh, sizeof(DFddh) +
  1114.                     (current->ddh.dds*sizeof(DFdd)), 1, dfile->file, -1);
  1115. #else /*DF_STRUCTOK*/
  1116.                 {
  1117.                     register  char *p;
  1118.                     p = DFtbuf;
  1119.                     INT16WRITE( p, current->ddh.dds);
  1120.                     INT32WRITE( p, current->ddh.next);
  1121.                     for (i=0; i<current->ddh.dds; i++) {
  1122.                         UINT16WRITE( p, current->dd[i].tag);
  1123.                         UINT16WRITE( p, current->dd[i].ref);
  1124.                         INT32WRITE( p, current->dd[i].offset);
  1125.                         INT32WRITE( p, current->dd[i].length);
  1126.                     }
  1127.                     CKWRITE( DFtbuf, 6+i*12, 1, dfile->file, -1);
  1128.                         /* 6= size of DDH, 12=size of DD */
  1129.                 }
  1130. #endif /*DF_STRUCTOK*/
  1131.             }
  1132.             prev=current;
  1133.         }
  1134.         DF_FLUSH(dfile->file);              /* ensure everything is written */
  1135.     }
  1136.     dfile->changed=0;
  1137.     return(0);
  1138. }   
  1139.  
  1140.  
  1141. /*-----------------------------------------------------------------------------
  1142.  * Name:    DFstat
  1143.  * Purpose: provide status information about DF file
  1144.  * Inputs:  dfile: pointer to open DF file
  1145.  *          dfinfo: ptr to space where to place information on HDF file
  1146.  * Returns: 0 on success, -1 on failure
  1147.  * Invokes: DFIcheck
  1148.  * Users:   HDF programmers
  1149.  *---------------------------------------------------------------------------*/
  1150.  
  1151. int DFstat(dfile, dfinfo)
  1152. DF *dfile;
  1153. struct DFdata *dfinfo;
  1154. {
  1155.  
  1156.     DFerror = DFE_NOERROR;
  1157.  
  1158.     if (DFIcheck(dfile) )
  1159.         return( -1);
  1160.  
  1161.         /* This is version number of program.  More will be added later */
  1162.     dfinfo->version = DFVERSION;
  1163.     return(0);
  1164. }
  1165.     
  1166.  
  1167. /*-----------------------------------------------------------------------------
  1168.  * Name:    DFgetelement
  1169.  * Purpose: read a data element from df file
  1170.  * Inputs:  dfile: pointer to open DF file
  1171.  *          tag, ref: id of data element
  1172.  *          ptr: space to put data element in
  1173.  * Returns: number of bytes read on success, -1 on failure
  1174.  * Invokes: DFaccess, DFread
  1175.  * Users:   HDF programmers, utilities, many other routines
  1176.  *---------------------------------------------------------------------------*/
  1177.  
  1178. int32 DFgetelement( dfile, tag, ref, ptr)
  1179. DF *dfile;
  1180. uint16 tag, ref;
  1181. char *ptr;
  1182. {
  1183.     if ( DFaccess( dfile, tag, ref, "r")<0) return((int32) -1);
  1184.     return( DFread( dfile, ptr, (int32) dfile->up_dd->length));
  1185. }
  1186.  
  1187.  
  1188. /*-----------------------------------------------------------------------------
  1189.  * Name:    DFputelement
  1190.  * Purpose: write a data element to df file
  1191.  * Inputs:  dfile: pointer to open DF file
  1192.  *          tag, ref: id of data element
  1193.  *          ptr: pointer to data element to be written
  1194.  *          len: length of data element
  1195.  * Returns: 0 on success, -1 on failure
  1196.  * Invokes: DFaccess, DFwrite
  1197.  * Users:   HDF programmers, utilities, many other routines
  1198.  *---------------------------------------------------------------------------*/
  1199.  
  1200. int DFputelement( dfile, tag, ref, ptr, len)
  1201. DF *dfile;
  1202. uint16 tag, ref;
  1203.  char *ptr;
  1204. int32 len;
  1205. {
  1206.     if ( DFaccess( dfile, tag, ref, "w")<0) return(-1);
  1207.     if( DFwrite( dfile, ptr, len)<0) return(-1);
  1208.     return(0);
  1209. }
  1210.  
  1211.  
  1212. /*-----------------------------------------------------------------------------
  1213.  * Name:    DFdup
  1214.  * Purpose: Add a new tag/ref for existing data
  1215.  * Inputs:  dfile: pointer to open DF file
  1216.  *          itag, iref: new id of data element
  1217.  *          otag, oref: current id of data element
  1218.  * Returns: 0 on success, -1 on failure
  1219.  * Invokes: DFIcheck, DFIfind, DFIemptyDD
  1220.  * Users:   HDF programmers, utilities, many other routines
  1221.  *---------------------------------------------------------------------------*/
  1222.  
  1223. int DFdup(dfile, itag, iref, otag, oref)
  1224. DF *dfile;
  1225. uint16 itag, iref, otag, oref;  /* new, existing tag/refs */
  1226. {
  1227.     DFdle *odlep, *idlep;
  1228.     int ocdd, icdd;
  1229.     DFdd *newdd;
  1230.  
  1231.     DFerror = DFE_NOERROR;
  1232.  
  1233.     if (DFIcheck(dfile) )
  1234.         return( -1);
  1235.  
  1236.     if (DFIfind( dfile, otag, oref, 1, 0, 0, &odlep, &ocdd)<0) {
  1237.         DFerror = DFE_NOMATCH;      /* existing tag/ref does not exist! */
  1238.         return(-1);
  1239.     }
  1240.  
  1241.     if (!DFIfind( dfile, itag, iref, 1, 0, 0, &idlep, &icdd))
  1242.         newdd = &idlep->dd[icdd];   /* replaces existing DD */
  1243.     else {
  1244.         newdd = DFIemptyDD(dfile);  /* find empty DD */
  1245.         if (!newdd) return(-1);
  1246.         newdd->tag = itag;
  1247.         newdd->ref = iref;
  1248.  
  1249.         if (DFmaxref < iref) DFmaxref = iref;       /* mark iref as used */
  1250.         if (DFreflist) DFreflist[iref/8] |= patterns[iref%8];
  1251.     }
  1252.     newdd->offset = odlep->dd[ocdd].offset;
  1253.     newdd->length = odlep->dd[ocdd].length;
  1254.     dfile->changed = 1;
  1255.     return(0);
  1256. }
  1257.  
  1258.  
  1259. /*-----------------------------------------------------------------------------
  1260.  * Name:    DFdel
  1261.  * Purpose: Delete a data element from file
  1262.  * Inputs:  dfile: pointer to open DF file
  1263.  *          tag, ref: id of data element
  1264.  * Returns: 0 on success, -1 on failure
  1265.  * Invokes: DFIcheck, DFIfind
  1266.  * Users:   HDF programmers, utilities, many other routines
  1267.  * Remarks: Data element is not deleted, only the reference to it is changed
  1268.  *---------------------------------------------------------------------------*/
  1269.  
  1270. int DFdel(dfile, tag, ref)
  1271. DF *dfile;
  1272. uint16 tag, ref;
  1273. {
  1274.     DFdle *dlep;
  1275.     int cdd;
  1276.  
  1277.     DFerror = DFE_NOERROR;
  1278.  
  1279.     if (DFIcheck(dfile) )
  1280.         return( -1);
  1281.  
  1282.     if (DFIfind( dfile, tag, ref, 1, 0, 0, &dlep, &cdd)<0) {
  1283.         DFerror = DFE_NOMATCH;      /* nothing to delete */
  1284.         return(-1);
  1285.     }
  1286.     dlep->dd[cdd].tag = DFTAG_NULL;
  1287.     dlep->dd[cdd].ref = 0;
  1288.     dfile->changed = 1;
  1289.     return(0);
  1290. }
  1291.  
  1292.  
  1293. /*-----------------------------------------------------------------------------
  1294.  * Name:    DFnewref
  1295.  * Purpose: Get an ununsed reference number
  1296.  * Inputs:  dfile: pointer to HDF file
  1297.  * Returns: unused ref number if found.  0 with DFerror set if not.
  1298.  * Users:   HDF programmers, for adding data elements
  1299.  * Invokes: DFIcheck
  1300.  * Remarks: Currently, returns a ref which is not used with any tag, except
  1301.  *          possibly DFTAG_MT
  1302.  *---------------------------------------------------------------------------*/
  1303.  
  1304. uint16 DFnewref(dfile)
  1305. DF *dfile;
  1306. {
  1307.     DFdle *DLEp;
  1308.     int i,j;
  1309.  
  1310.     DFerror = DFE_NOERROR;
  1311.  
  1312.     if (DFIcheck(dfile) )
  1313.         return ((uint16) 0);
  1314.  
  1315.     if (DFmaxref < 65535)       /* 65535 = largest 16-bit uint = largest ref */
  1316.         return(++DFmaxref);
  1317.  
  1318.     /* allocate a bit array of 65536 bits - one for each ref */
  1319.     if (DFreflist==NULL) {
  1320.         if ((DFreflist = (unsigned char *) DFIgetspace(8192)) == NULL)
  1321.                 return((uint16) 0);             /* 8192 = 65536/8 */
  1322.         
  1323.         for (i=1; i<8192; i++) DFreflist[i] = 0;    /* initialize */
  1324.         DFreflist[0] = 0x80;            /* ref 0 is not to be allocated */
  1325.  
  1326.         for (DLEp=dfile->list; DLEp; DLEp=DLEp->next) /* go through all DDs */
  1327.             for (i=0; i<DLEp->ddh.dds; i++)
  1328.                 if (DLEp->dd[i].tag != DFTAG_MT)    /* set ref'th bit to 1 */
  1329.                     DFreflist[DLEp->dd[i].ref/8] |=
  1330.             patterns[DLEp->dd[i].ref%8];
  1331.     }
  1332.  
  1333.     for (i=0; i<8192; i++)
  1334.         if (DFreflist[i] != 0xff) break; /* if ff, all refs taken */
  1335.  
  1336.     if (i==8192) {
  1337.         DFerror = DFE_NOREF;
  1338.         return((uint16) 0);
  1339.     }
  1340.  
  1341.     for (j=0; j<8; j++) {
  1342.         if (!(DFreflist[i] & patterns[j])) { /* ref j is not allocated */
  1343.             DFreflist[i] |= patterns[j]; /* ref j is now in use */
  1344.             return((uint16) (i*8 + j));    /* ref to use */
  1345.         }
  1346.     }
  1347.  
  1348.     return((uint16) 0);        /* this statement should not be reached */
  1349. }
  1350.  
  1351.  
  1352. /*-----------------------------------------------------------------------------
  1353.  * Name:    DFishdf
  1354.  * Purpose: Is this an HDF file?
  1355.  * Inputs:  filename: name of HDF file
  1356.  * Returns: 0 if it is an HDF file, -1 if not.  DFerror is set to open error
  1357.  *              if any, else to DFE_NOERROR
  1358.  * Users:   HDF systems programmers, for checking files
  1359.  * Invokes: DFopen, DFclose
  1360.  * Remarks: none
  1361.  *---------------------------------------------------------------------------*/
  1362.  
  1363. DFishdf(filename)
  1364. char *filename;
  1365. {
  1366.     DF *dfile;
  1367.  
  1368.     DFerror = DFE_NOERROR;
  1369.  
  1370.     dfile = DFopen(filename, DFACC_READ, -1);
  1371.     if (dfile==NULL) return(-1);
  1372.     return(DFclose(dfile));
  1373. }
  1374.  
  1375.  
  1376. /*-----------------------------------------------------------------------------
  1377.  * Name:    DFerrno
  1378.  * Purpose: return value of DFerror
  1379.  * Inputs:  none
  1380.  * Returns: value of DFerror
  1381.  * Users:   HDF users, programmers
  1382.  * Invokes: none
  1383.  * Remarks: none
  1384.  *---------------------------------------------------------------------------*/
  1385.  
  1386. int DFerrno()
  1387. {
  1388.  
  1389.     return(DFerror);
  1390. }
  1391.  
  1392.  
  1393. /*-----------------------------------------------------------------------------
  1394.  * Name:    DFIerr
  1395.  * Purpose: Close a file and return on error. save DFerror
  1396.  * Inputs:  dfile: pointer to HDF file to close
  1397.  * Returns: -1
  1398.  * Users:   HDF systems programmers, for error handling
  1399.  * Invokes: DFclose
  1400.  * Remarks: Used to centralize some error handling
  1401.  *---------------------------------------------------------------------------*/
  1402.  
  1403. int DFIerr(dfile)
  1404. DF *dfile;
  1405. {
  1406.     int saveerror;
  1407.  
  1408.     saveerror = DFerror;
  1409.     if (dfile!=NULL) (void) DFclose(dfile);
  1410.     DFerror = saveerror;
  1411.     return(-1);
  1412. }
  1413.